#include <stdint.h>
#include <string.h>

#define CIRBUF_N  1024      // item number

typedef struct
{
    uint8_t buf[CIRBUF_N];
    int     wrptr;          // 写指针
    int     rdptr;          // 读指针
} CircleBuffer_t;

/* Element Count in Buffer */
static int CirBuf_Count(CircleBuffer_t *cirbuf)
{
    return (cirbuf->wrptr - cirbuf->rdptr) & (CIRBUF_N - 1);
}

/* Space available in Buffer. 留一个空位表示满，以区别于空 */
static int CirBuf_Space(CircleBuffer_t *cirbuf)
{
    return (cirbuf->rdptr - cirbuf->wrptr - 1) & (CIRBUF_N - 1);
}

static int CirBuf_Empty(CircleBuffer_t *cirbuf)
{
    return CirBuf_Count(cirbuf) == 0;
}

static int CirBuf_Full(CircleBuffer_t *cirbuf)
{
    return CirBuf_Space(cirbuf) == (CIRBUF_N - 1);
}

static int CirBuf_Write(CircleBuffer_t *cirbuf, uint8_t *buf, int num)
{
    int n;

    if(cirbuf->wrptr >= cirbuf->rdptr)
    {
        if(cirbuf->rdptr == 0)
            n = (CIRBUF_N - 1) - cirbuf->wrptr;
        else
            n = CIRBUF_N - cirbuf->wrptr;
        
        n = (n >= num) ? num : n;

        memcpy(&cirbuf->buf[cirbuf->wrptr], buf, n);

        cirbuf->wrptr = (cirbuf->wrptr + n) % CIRBUF_N;

        if((n == num) || CirBuf_Full(cirbuf))
            return n;
        else
            return n + CirBuf_Write(cirbuf, &buf[n], num - n);
    }
    else
    {
        n = (cirbuf->rdptr - 1) - cirbuf->wrptr;

        n = (n >= num) ? num : n;

        memcpy(&cirbuf->buf[cirbuf->wrptr], buf, n);

        cirbuf->wrptr += n;

        return n;
    }
}

static int CirBuf_Read(CircleBuffer_t *cirbuf, uint8_t *buf, int num)
{
    int n;

    if(cirbuf->wrptr >= cirbuf->rdptr)
    {
        n = cirbuf->wrptr - cirbuf->rdptr;

        n = (n >= num) ? num : n;

        memcpy(buf, &cirbuf->buf[cirbuf->rdptr], n);

        cirbuf->rdptr += n;

        return n;
    }
    else
    {
        n = CIRBUF_N - cirbuf->rdptr;

        n = (n >= num) ? num : n;

        memcpy(buf, &cirbuf->buf[cirbuf->rdptr], n);

        cirbuf->rdptr = 0;

        if((n == num) || CirBuf_Empty(cirbuf))
            return n;
        else
            return n + CirBuf_Read(cirbuf, &buf[n], num-n);
    }
}
